package org.papervision3d.objects
{
	import flash.display.BlendMode;
	
	import org.papervision3d.Papervision3D;
	import org.papervision3d.core.culling.FrustumTestMethod;
	import org.papervision3d.core.data.UserData;
	import org.papervision3d.core.geom.renderables.Triangle3D;
	import org.papervision3d.core.log.PaperLogger;
	import org.papervision3d.core.material.AbstractLightShadeMaterial;
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.core.math.Number3D;
	import org.papervision3d.core.math.Quaternion;
	import org.papervision3d.core.proto.CameraObject3D;
	import org.papervision3d.core.proto.DisplayObjectContainer3D;
	import org.papervision3d.core.proto.GeometryObject3D;
	import org.papervision3d.core.proto.MaterialObject3D;
	import org.papervision3d.core.proto.SceneObject3D;
	import org.papervision3d.core.render.data.RenderSessionData;
	import org.papervision3d.materials.shaders.ShadedMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.view.Viewport3D;
	import org.papervision3d.view.layer.ViewportLayer;

	/**
	* <div lang="ja">DisplayObject クラスは、Scene3D の表示リストに含めることのできるすべてのオブジェクトに関する基本クラスです。
	* レンダリングされているものだけでなく、カメラとそのターゲットも含んでいます。
	* <p/>
	* DisplayObject3D クラスはオブジェクトの x,y,z 位置、rotationX, rotationY, rotationZ, そして scaleX, scaleY, scaleZ と visible をサポートします。
	* transform Matrix3D の様な、オブジェクトの高度なプロパティもサポートしています。
	* <p/>
	* DiaplayObject3D は抽象基本クラスではありません。そのため、DisplayObject3D を直接呼び出す事ができます。
	* new DisplayObject() は 3D 空間に新しい空のオブジェクトを作成します。空のムービークリップを作成する時に使用する様なものです。
	* </div>
	* 
	* <div lang="en">
	* The DisplayObject class represents instances of 3D objects that are contained in the scene.
	* <p/>
	* That includes all objects in the scene, not only those that can be rendered, but also the camera and its target.
	* <p/>
	* The DisplayObject3D class supports basic functionality like the x, y and z position of an object, as well as rotationX, rotationY, rotationZ, scaleX, scaleY and scaleZ and visible. 
	* It also supports more advanced properties of the object such as its transform Matrix3D.
	* <p/>
	* <p/>
	* DisplayObject3D is not an abstract base class; therefore, you can call DisplayObject3D directly. 
	* Invoking new DisplayObject() creates a new empty object in 3D space, like when you used createEmptyMovieClip().
	* </div>
	*/
	public class DisplayObject3D extends DisplayObjectContainer3D
	{
	   /**
		* <span lang="ja">Mesh3D の render() メソッドを三角形の中央からソートします。</span>
		* <span lang="en">tells Mesh3D's render() method to sort by measuring from the center of a triangle</span>
		*/
		public static const MESH_SORT_CENTER:uint = 1;
		
		/**
		* <span lang="ja">Mesh3D の render() メソッドを三角形の最も遠いポイントからソートします。</span>
		* <span lang="en">tells Mesh3D's render() method to sort by measuring from the farthest point of a triangle</span>
		*/
		public static const MESH_SORT_FAR:uint = 2;
		
		/**
		* Mesh3D の render() メソッドを三角形の最も近いポイントからソートします。
		* <span lang="en">tells Mesh3D's render() method to sort by measuring from the closest point of a triangle</span>
		*/
		public static const MESH_SORT_CLOSE:uint = 3;
		
		/**
		* <span lang="ja">Matrix3D オブジェクトはディスプレイオブジェクトのスケール,rotation,translation の値を格納します。</span>
		* <span lang="en">A Matrix3D object containing values that affect the scaling, rotation, and translation of the display object.</span>
		*/
		public var transform :Matrix3D;
	
		/**
		* [internal-use] カメラを Matrix3D オブジェクトに変化させます。
		* [internal-use] A camera transformed Matrix3D object.
		*/
		public var view      :Matrix3D;
	
		/**
		* ワールド変換の行列です。
		* <span lang="en">World transformation.</span>
		*/
		public var world     :Matrix3D;
	
		/**
		* [internal-use]
		*/
		public var faces     :Array = new Array();
	
		/**
		 * これはオブジェクトの表面がオブジェクト自体のコンテナを持つ事を可能にします。
		 * <span lang="en">This allows objects faces to have their own containers.</span>
		 */
		public static var faceLevelMode  :Boolean;
		
		public static var sortedArray:Array = new Array();
		
		/**
		* このインスタンスの3D定義を格納する GeometryObject3D オブジェクトです。
		* 異なるオブジェクトが同じジオメトリーを共有する場合、それらはインスタンスになります。
		* それらは同じオブジェクトなので何度も表示されます。
		* このオブジェクトのシェイプを替える事は、その全てのインスタンスのシェイプを替える事になります。
		* インスタンス化するオブジェクトはシステムメモリーを保存し、そのシェイプを維持する間、何度もオブジェクトを表示するのに役立ちます。
		* 例えば、あなたが複製オブジェクトでいっぱいの兵隊と木々を作成するのに、実際のジオメトリーにマッチする処理にメモリーを必要としません。
		* 各インスタンスがそれぞれトランスフォームノードを持つので、それらの位置、回転、スケールを持つ事が出来るのです。
		* 
		* <div lang="en">
		* The GeometryObject3D object that contains the 3D definition of this instance.
		* <p/>
		* When different objects share the same geometry, they become instances. 
		* They are the same object, displayed multiple times. Changing the shape of this object changes the shape of all of its instances.
		* <p/>
		* Instancing an object saves system memory, and is useful to display an object multiple times while maintaining its shape.
		* <p/>
		* For example, you could create armies and forests full of duplicate objects without needing the memory to handle that much actual geometry. 
		* Each instance has its own transform node so it can have its own position, rotation, and scaling.
		* </div>
		*/
		public var geometry :GeometryObject3D;
	
		/**
		* [internal-use] オブジェクトの平均深度を中央に向かせます。内部のz-ソーティングに使用されます。 
		* <span lang="en">The average depth of the object faces center. Used internally for z-sorting.</span>
		*/
		public var screenZ :Number;
	
		/**
		* [internal use] このオブジェクトはカメラの視錐台によってカリングされますか？ 
		* <span lang="en">Is this object culled by camera frustum?</span>
		*/
		public var culled:Boolean;
		
		/**
		* このインスタンスのためのマテリアルのリスト
		* <span lang="en">The list of materials for this instance.</span>
		*/
		public var materials   :MaterialsList;
		
		/**
		* Mesh3D の render() メソッドは、三角形のソーティングのためにユーザーが選択した長さを比較します。
		* <span lang="en">tells Mesh3D's render() method to compare the measurement choice of the user for a triangle's sorting</span>
		*/
		public var meshSort:uint = MESH_SORT_CENTER;
		
		public var container			:ViewportLayer;	
		/**
		 * 指定されたオブジェクトのアルファ透明度値を示します。
		 */
		public var alpha				:Number = 1;
		/**
		 * 使用するブレンドモードを指定する BlendMode クラスの値です。
		 */
		public var blendMode			:String = BlendMode.NORMAL;
		/**
		 * 表示オブジェクトに現在関連付けられている各フィルタオブジェクトが格納されているインデックス付きの配列です。
		 */
		public var filters				:Array = [];
		public var parentContainer		:DisplayObject3D;
		public var flipLightDirection	:Boolean = false;
		public var frustumTestMethod	:int = FrustumTestMethod.BOUNDING_SPHERE;
		
		/**
		* [読み取り専用] この表示オブジェクトを含む DisplayObjectContainer3D オブジェクトを示します。 
		* <span lang="en">Indicates the DisplayObjectContainer3D object that contains this display object.</span>
		*/
		public var parent :DisplayObjectContainer3D;
		
		/**
		* [読み取り専用] スクリーン上のオブジェクトの座標です。 
		* <span lang="en">coordinate of the object on screen.</span>
		*/
		public var screen :Number3D = new Number3D();
	
		/**
		* 表示オブジェクトが可視かどうかを示します。
		* 
		* <span lang="en">Whether or not the display object is visible.</span>
		* <span lang="en">A Boolean value that indicates whether the object is projected, transformed and rendered. </span>
		* <span lang="en">A value of false will effectively ignore the object. The default value is true.</span>
		*/
		public var visible :Boolean;
	
		/**
		* DisplayObject3D のインスタンス名を示します。
		* <span lang="en">An optional object name.</span>
		*/
		public var name :String;
	
		/**
		* [読み取り専用] DisplayObject3D インスタンスのユニーク ID です。
		* <span lang="en">Unique id of this instance.</span>
		*/
		public var id :int;

		/**
		* ユーザーが定義したプロパティを格納するオブジェクトです。
		* 追加した領域の全てのプロパティは新しいインスタンスにコピーされます。
		* 追加で指定されたプロパティは public に利用できます。
		* 
		* <span lang="en">An object that contains user defined properties.</span>
		* <p/>
		* <span lang="en">All properties of the extra field are copied into the new instance. 
		* The properties specified with extra are publicly available.</span>
		*/
		public var extra :Object; // = {}; TBD
		
		
		public var cullTest:Number = 0;
		/**
		 * クリッピングを使用するかを取得または設定します。
		 */
		public var useClipping:Boolean = true;
		
		public var testQuad:Boolean = true;
				
		/**
		* Relative directions.
		*/
		static private const FORWARD  	:Number3D = new Number3D(  0,  0,  1 );
		static private const BACKWARD 	:Number3D = new Number3D(  0,  0, -1 );
		static private const LEFT     	:Number3D = new Number3D( -1,  0,  0 );
		static private const RIGHT    	:Number3D = new Number3D(  1,  0,  0 );
		static private const UP       	:Number3D = new Number3D(  0,  1,  0 );
		static private const DOWN     	:Number3D = new Number3D(  0, -1,  0 );
		
		private static var _tempMatrix	:Matrix3D = Matrix3D.IDENTITY; 
		private static var _tempQuat	:Quaternion = new Quaternion(); 
		private static var _newID		:int = 0;
		private static var toDEGREES 	:Number = 180/Math.PI;
		private static var toRADIANS 	:Number = Math.PI/180;
		private static var entry_count	:uint = 0;
		
		/**
		* @private
		*/
		protected var _transformDirty 	:Boolean = false;
		/**
		* @private
		*/
		protected var _sorted       	:Array;
		/**
		* @private
		*/
		protected var _useOwnContainer	:Boolean = false;
		/**
		* @private
		*/
		protected var _userData			:UserData;
		
		/**
		* オブジェクトに所属する scene です。
		* <span lang="en">The scene where the object belongs.</span>
		*/
		protected var _scene 			:SceneObject3D = null;
			
		/**
		 * lookAt 関数などで使用するため、先に作成された Number3D とMatrix3D です。
		 * 
		 * <span lang="en">pre-made Number3Ds and Matrix3Ds for use in the lookAt function
		 * and others</span>
		 * 
		 */
		private	var _position 			:Number3D = Number3D.ZERO;
		private	var _lookatTarget   	:Number3D = Number3D.ZERO;
		private	var _zAxis 				:Number3D = Number3D.ZERO;
		private	var _xAxis 				:Number3D = Number3D.ZERO;
		private	var _yAxis 				:Number3D = Number3D.ZERO;
		private var _rotation			:Number3D  = Number3D.ZERO; 
		private var _rotationDirty  	:Boolean = false;
		private var _rotationX      	:Number;
		private var _rotationY     	 	:Number;
		private var _rotationZ      	:Number;
		private var _scaleX         	:Number;
		private var _scaleY         	:Number;
		private var _scaleZ         	:Number;
		private var _scaleDirty     	:Boolean = false;
		private var _tempScale			:Number3D;
		private var _numClones			:uint	= 0;
		private var _material			:MaterialObject3D;
		private var _rot				:Quaternion = new Quaternion();
		
		private var _qPitch		:Quaternion = new Quaternion();
		private var _qYaw		:Quaternion = new Quaternion();
		private var _qRoll		:Quaternion = new Quaternion();
		
		private var _localRotationX	:Number = 0;
		private var _localRotationY	:Number = 0;
		private var _localRotationZ	:Number = 0;
		
		private var _autoCalcScreenCoords:Boolean = false;
		/**
		* 3D座標系(0,0,0)の中央に配置された空の DisplayObject3D オブジェクトを取得します。
		* <span lang="en">Returns an empty DiplayObject3D object positioned in the center of the 3D coordinate system (0, 0 ,0).</span>
		*/
		static public function get ZERO():DisplayObject3D
		{
			return new DisplayObject3D();
		}
		
		/**
		 * 親のコンテナーを利用してプロパティ－を適用するかどうかを取得または設定します。
		 * <p/>
		 * true の場合は alpha や filters のプロパティーを親のコンテナーを利用して適用します。
		 * <p/>
		 * false の場合は alpha や filters のプロパティーは適用されません。
		 */
		public function get useOwnContainer():Boolean
		{
			return _useOwnContainer;
		}
		
		public function set useOwnContainer(value:Boolean):void
		{
			_useOwnContainer = value;
			setParentContainer(this, true);
		}
		
		public function set userData(userData:UserData):void
		{
			_userData = userData;
		}
		
		public function get userData():UserData
		{
			return _userData;	
		}
		
		/**
		* 親 DisplayObjectContainer3D のローカル座標を基準にした DisplayObject3D インスタンスの x 座標を示します。
		* <span lang="en">An Number that sets the X coordinate of a object relative to the origin of its parent.</span>
		*/
		public function get x():Number
		{
			return this.transform.n14;
		}
	
		public function set x( value:Number ):void
		{
			this.transform.n14 = value;
		}
		
		/**
		* 親 DisplayObjectContainer3D のローカル座標を基準にした DisplayObject3D インスタンスの y 座標を示します。
		* <span lang="en">An Number that sets the Y coordinate of a object relative to the origin of its parent.</span>
		*/
		public function get y():Number
		{
			return this.transform.n24;
		}
	
		public function set y( value:Number ):void
		{
			this.transform.n24 = value;
		}
	
		/**
		* 親 DisplayObjectContainer3D のローカル座標を基準にした DisplayObject3D インスタンスの z 座標を示します。
		* <span lang="en">An Number that sets the Z coordinate of a object relative to the origin of its parent.</span>
		*/
		public function get z():Number
		{
			return this.transform.n34;
		}
	
		public function set z( value:Number ):void
		{
			this.transform.n34 = value;
		}
		
		/**
		 * DisplayObject3D の最新の x,y,z を格納する Number3D を取得または設定します。
		 * <span lang="en">A Number3D containing the current x, y, and z of the DisplayObject3D</span>
		 */
		 
		 public function get position():Number3D
		 {
		 	_position.reset(this.x, this.y, this.z);
		 	return _position;
		}

		public function set position(n:Number3D):void
		 {
		 	this.x = n.x;
		 	this.y = n.y;
		 	this.z = n.z;
		 }
		 
		/**
		* DisplayObject3D インスタンスの 3D 親コンテナを基準にした元の位置からの x 軸の回転角を度単位で示します。
		* <span lang="en">Specifies the rotation around the X axis from its original orientation.</span>
		*/
		public function get rotationX():Number
		{
			if( this._rotationDirty ) updateRotation();
	
			return Papervision3D.useDEGREES ? this._rotationX * toDEGREES : this._rotationX;
		}
	
		public function set rotationX( rot:Number ):void
		{
			this._rotationX = Papervision3D.useDEGREES ? rot * toRADIANS : rot;

			this._transformDirty = true;
		}
	
		/**
		* DisplayObject3D インスタンスの 3D 親コンテナを基準にした元の位置からの y 軸の回転角を度単位で示します。
		* <span lang="en">Specifies the rotation around the Y axis from its original orientation.</span>
		*/
		public function get rotationY():Number
		{
			if( this._rotationDirty ) updateRotation();
	
			return Papervision3D.useDEGREES ? this._rotationY * toDEGREES : this._rotationY;
		}
	
		public function set rotationY( rot:Number ):void
		{
			this._rotationY = Papervision3D.useDEGREES ? rot * toRADIANS : rot;
		
			this._transformDirty = true;
		}
	
		/**
		* DisplayObject3D インスタンスの 3D 親コンテナを基準にした元の位置からの z 軸の回転角を度単位で示します。
		* <span lang="en">Specifies the rotation around the Z axis from its original orientation.</span>
		*/
		public function get rotationZ():Number
		{
			if( this._rotationDirty ) updateRotation();
	
			return Papervision3D.useDEGREES ? this._rotationZ * toDEGREES : this._rotationZ;
		}
	
		public function set rotationZ( rot:Number ):void
		{
			this._rotationZ = Papervision3D.useDEGREES ? rot * toRADIANS : rot;
			
			this._transformDirty = true;
		}

		// ___________________________________________________________________ S C A L E
	
		/**
		* 基準点から適用されるオブジェクトのスケールを示します。
		* <span lang="en">Sets the 3D scale as applied from the registration point of the object.</span>
		*/
		public function get scale():Number
		{
			if( this._scaleX == this._scaleY && this._scaleX == this._scaleZ )
				if( Papervision3D.usePERCENT ) return this._scaleX * 100;
				else return this._scaleX;
			else return NaN;
		}
	
		public function set scale( scale:Number ):void
		{
			if( this._rotationDirty ) updateRotation();
			
			
			if( Papervision3D.usePERCENT ) scale /= 100;
	
			this._scaleX = this._scaleY = this._scaleZ = scale;
	
			this._transformDirty = true;
		}
	
	
		/**
		* 基準点から適用されるオブジェクトの x 軸スケールを示します。
		* <span lang="en">Sets the scale along the local X axis as applied from the registration point of the object.</span>
		*/
		public function get scaleX():Number
		{
			if( Papervision3D.usePERCENT ) return this._scaleX * 100;
			else return this._scaleX;
		}
	
		public function set scaleX( scale:Number ):void
		{
			if( this._rotationDirty ) updateRotation();
			
			if( Papervision3D.usePERCENT ) this._scaleX = scale / 100;
			else this._scaleX = scale;
	
			this._transformDirty = true;
		}
	
		/**
		* 基準点から適用されるオブジェクトの y 軸スケールを示します。
		* <span lang="en">Sets the scale along the local Y axis as applied from the registration point of the object.</span>
		*/
		public function get scaleY():Number
		{
			if( Papervision3D.usePERCENT ) return this._scaleY * 100;
			else return this._scaleY;
		}
	
		public function set scaleY( scale:Number ):void
		{
			if( this._rotationDirty ) updateRotation();
			
			if( Papervision3D.usePERCENT ) this._scaleY = scale / 100;
			else this._scaleY = scale;
	
			this._transformDirty = true;
		}
	
		/**
		* 基準点から適用されるオブジェクトの z 軸スケールを示します。
		* <span lang="en">Sets the scale along the local Z axis as applied from the registration point of the object.</span>
		*/
		public function get scaleZ():Number
		{
			if( Papervision3D.usePERCENT ) return this._scaleZ * 100;
			else return this._scaleZ;
		}
	
		public function set scaleZ( scale:Number ):void
		{
			if( this._rotationDirty ) updateRotation();
			
			if( Papervision3D.usePERCENT ) this._scaleZ = scale / 100;
			else this._scaleZ = scale;
	
			this._transformDirty = true;
		}
	
		
		
	
		/**
		* scene 座標系に関連付けられたオブジェクトの X 座標です。
		* <span lang="en">The X coordinate of a object relative to the scene coordinate system.</span>
		*/
		public function get sceneX():Number
		{
			return this.world.n14;
		}
	
		/**
		* scene 座標系に関連付けられたオブジェクトの Y 座標です。
		* <span lang="en">The Y coordinate of a object relative to the scene coordinate system.</span>
		*/
		public function get sceneY():Number
		{
			return this.world.n24;
		}
	
		/**
		* scene 座標系に関連付けられたオブジェクトの Z 座標です。
		* <span lang="en">The Z coordinate of a object relative to the scene coordinate system.</span>
		*/
		public function get sceneZ():Number
		{
			return this.world.n34;
		}

		/**
		* オブジェクトインスタンスのデフォルトマテリアルです。どの様にオブジェクトがレンダリングされるかのデータを集めます。
		* <span lang="en">The default material for the object instance. Materials collect data about how objects appear when rendered.</span>
		*/
		public function set material(material:MaterialObject3D):void
		{
			if(_material){
				_material.unregisterObject(this);
			}
			_material = material;
			if (_material){
				_material.registerObject(this);
			}
		}
		
		public function get material():MaterialObject3D
		{
			return _material;
		}
		
		public function set scene(p_scene:SceneObject3D):void
		{
			// set scene property
			_scene = p_scene;
			
			for each( var child:DisplayObject3D in this._childrenByName )
			{
				if(child.scene == null) child.scene = _scene;
			}
		}
		
		public function get scene():SceneObject3D
		{
			return _scene;
		}
		
		
		/**
		 * 自動的にスクリーン座標を計算するかどうかを取得または設定します。
		 * autoCalcScreenCoords を true にした場合には、screenX または screenY で Viewport 上の X, Y 座標を取得することができます。
		 */
		public function get autoCalcScreenCoords():Boolean
		{
			return _autoCalcScreenCoords ;
		}
		public function set autoCalcScreenCoords(autoCalculateScreenCoords:Boolean):void
		{
			_autoCalcScreenCoords = autoCalculateScreenCoords;
		}
		
	
		/**
		* 新しい DisplayObject3D インスタンスを作成します。
		* <span lang="en">Creates a new DisplayObject3D instance. After creating the instance, call the addChild() method of a DisplayObjectContainer3D.</span>
		*
		* @param	name		[optional] - The name of the newly created object.
		* @param	geometry	[optional] - The geometry of the newly created object.
		*/
		public function DisplayObject3D( name:String=null, geometry:GeometryObject3D=null ):void
		{
			super();
			
			if(name!=null){
				PaperLogger.info( "DisplayObject3D: " + name );
			}
			this.culled    = false;
			
			this.transform = Matrix3D.IDENTITY;
			this.world     = Matrix3D.IDENTITY;
			this.view      = Matrix3D.IDENTITY;
	
			this.x =  0;
			this.y =  0;
			this.z =  0;
			
			rotationX = 0;
			rotationY = 0;
			rotationZ = 0;
	
			_localRotationX = _localRotationY = _localRotationZ = 0;
			
			var scaleDefault:Number = Papervision3D.usePERCENT? 100 : 1;
			scaleX = scaleDefault;
			scaleY = scaleDefault;
			scaleZ = scaleDefault;
			_tempScale = new Number3D();
			
			this.visible = true;
	
			this.id = _newID++;
			this.name = name || String( this.id );
	
			_numClones = 0;
			
			if( geometry ) addGeometry( geometry );
		}
	
		
		/**
		* <span lang="ja">この DisplayObjectContainer3D インスタンスに子 DisplayObject3D インスタンスを追加します。</span>
		* <span lang="en">Adds a child DisplayObject3D instance to this DisplayObjectContainer instance.</span>
		*
		* [TODO: If you add a child object that already has a different display object container as a parent, the object is removed from the child list of the other display object container.]
		*
		* @param	child	この DisplayObjectContainer3D インスタンスの子として追加する DisplayObject3D インスタンスです。
		* @param	name	An optional name of the child to add or create. If no name is provided, the child name will be used.
		* @return	child パラメータで渡す DisplayObject3D インスタンスです。
		*/
		public override function addChild( child :DisplayObject3D, name:String=null ):DisplayObject3D
		{
			child = super.addChild( child, name );
			
			if( child.scene == null ) child.scene = scene;
			if( this.useOwnContainer){
					child.parentContainer = this;
			}
			return child;
		}
		
		/**
		* <span lang="ja">インスタンスにジオメトリー定義を追加します。</span>
		* <span lang="en">Adds a geometry definition to the instance.</span>
		*
		* ジオメトリーが scene の中のオブジェクトのビジュアルシェイプとアピアレンスを描写します。
		* <span lang="en">A geometry describes the visual shape and appearance of an object in a scene.</span>
		*
		* @param	geometry	A geometry definition.
		*/
		public function addGeometry( geometry:GeometryObject3D=null ):void
		{
			if( geometry )
				this.geometry = geometry;	
		}
		
		/**
		 * <span lang="ja">DisplayObject3D インスタンスのコピーを作成して、各プロパティの値を元のプロパティの値と一致するように設定します。</span>
		 * 
		 * @return
		 * 	<span lang="ja">元のオブジェクトと同じプロパティ値を含む新しい DisplayObject3D インスタンスです。</span>
		 * 	<span lang="en">The cloned DisplayObject3D.</span>
		 */ 
		public function clone():DisplayObject3D
		{
			var name:String = this.name + "_" + (_numClones++);
			var object:DisplayObject3D = new DisplayObject3D(name);

			if(this.material)
				object.material = this.material;
			
			if(this.materials)
				object.materials = this.materials.clone();
				
			if(this.geometry)
			{
				object.geometry = this.geometry.clone(object);
				object.geometry.ready = true;
			}
			
			object.copyTransform(this);
			
			for each(var child:DisplayObject3D in this.children)
				object.addChild(child.clone());
				
			return object;
		}
		

		/**
		* <span lang="ja">引数で受け取ったオブジェクトとの距離を計測します。</span>
		* <span lang="en">Gets the distance to the position of the given object.</span>
		*
		* @param	obj		
		* 	<span lang="ja">距離を計測したい対象のオブジェクト</span>
		* 	<span lang="en">The display object to measure the distance to.</span>
		* @return
		* 	<span lang="ja">引数で受け取ったオブジェクトとの距離</span>
		* 	<span lang="en">The distance to the registration point of the given object.</span>
		*/
		public function distanceTo( obj:DisplayObject3D ):Number
		{
			var x :Number = this.x - obj.x;
			var y :Number = this.y - obj.y;
			var z :Number = this.z - obj.z;
	
			return Math.sqrt( x*x + y*y + z*z );
		}
	
	
		/**
		* <span lang="ja">表示オブジェクトを評価して、x, y, z パラメータで指定されたポイントと重複または交差するかどうかを調べます。</span>
		* <span lang="en">Evaluates the display object to see if it overlaps or intersects with the point specified by the x, y and z parameters.</span>
		* <p/>
		* <span lang="en">The x, y and z parameters specify a point in the coordinate space of the instance parent object, not the scene (unless that parent object is the scene).</span>
		*
		* @param	x	The x coordinate to test against this object.
		* @param	y	The y coordinate to test against this object.
		* @param	z	The z coordinate to test against this object.
		* @return	true if the display object overlaps or intersects with the specified point; false otherwise.
		*/
		public function hitTestPoint( x:Number, y:Number, z:Number ):Boolean
		{
			var dx :Number = this.x - x;
			var dy :Number = this.y - y;
			var dz :Number = this.z - z;
	
			var d2 :Number = dx*dx + dy*dy + dz*dz;
	
			var sA :Number = this.geometry? this.geometry.boundingSphere.maxDistance : 0;
	
			return sA > d2;
		}
	
	
		/**
		* <span lang="ja">表示オブジェクトの境界ボックスを評価して、obj 表示オブジェクトの境界ボックスと重複または交差するかどうかを調べます。</span>
		* <span lang="en">Evaluates the display object to see if it overlaps or intersects with the obj display object.</span>
		*
		* @param	obj	 The display object to test against.
		* @return	true if the display objects intersect; false if not.
		*/
		// TODO: Use group boundingSphere
		public function hitTestObject( obj:DisplayObject3D, multiplier:Number=1 ):Boolean
		{
			var dx :Number = this.x - obj.x;
			var dy :Number = this.y - obj.y;
			var dz :Number = this.z - obj.z;
	
			var d2 :Number = dx*dx + dy*dy + dz*dz;
	
			var sA :Number = this.geometry? this.geometry.boundingSphere.maxDistance : 0;
			var sB :Number = obj.geometry?  obj.geometry.boundingSphere.maxDistance  : 0;
			
			sA = sA * multiplier;
	
			return sA + sB > d2;
		}
	
		// ___________________________________________________________________________________________________
		//                                                                                   M A T E R I A L S
	
		/**
		* <span lang="ja">マテリアルリストで指定された名前でマテリアルを取得します。</span>
		* <span lang="ja">指定された名前を持つマテリアルオブジェクトが更にあったら、マテリアルリストの最初のマテリアルオブジェクトを取得します。</span>
		* <span lang="en">Returns the material that exists with the specified name in the materials list.</span>
		* <span lang="en">If more that one material object has the specified name, the method returns the first material object in the materials list.</span>
		* @param	name	The name of the material to return.
		* @return	The material object with the specified name.
		*/
		// TODO: Recursive
		public function getMaterialByName( name:String ):MaterialObject3D
		{
			var material:MaterialObject3D = this.materials ? this.materials.getMaterialByName( name ) : null;
			if( material )
			{
				return material;
			}
			else
			{
				for each( var child :DisplayObject3D in this._childrenByName )
				{
					material = child.getMaterialByName( name );
					if( material ) return material;
				}
			}
			return null;
		}
	
		/**
		* <span lang="ja">マテリアルリストのマテリアル名のリストで string 値を取得します。</span>
		* <span lang="en">Returns a string value with the list of material names of the materials list.</span>
		*
		* @return	A string.
		*/
		// TODO: Recursive
		public function materialsList():String
		{
			var list:String = "";
	
			for( var name:String in this.materials )
				list += name + "\n";
	
			for each( var child :DisplayObject3D in this._childrenByName )
			{
				for( name in child.materials.materialsByName )
					list += "+ " + name + "\n";
			}
	
			return list;
		}
		
		
		/**
		 * <span lang="ja">マテリアルをその名前で置き換えます。</span>
		 * <span lang="en">Replaces a material by its name.</span>
		 * 
		 * @param	material
		 * @param	name
		 * @return
		 */
		public function replaceMaterialByName(material:MaterialObject3D, name:String):void
		{
			if(!this.materials)
				return;
			
			var existingMaterial:MaterialObject3D = this.materials.getMaterialByName(name);
			if(!existingMaterial)
				return;
				
			if(this.material === existingMaterial)
				this.material = material;
			existingMaterial = this.materials.removeMaterial(existingMaterial);
	
			material = this.materials.addMaterial(material, name);
				
			updateMaterials(this, existingMaterial, material);
		}
		
		/**
		 * <span lang="ja">子 DisplayObject3D のためにマテリアルを設定します。</span>
		 * <span lang="en">Sets the material for a child DisplayObject3D.</span>
		 * 
		 * @param child		A child DisplayObject3D of this DAE.
		 * @param material	The new material for the child.
		 * @param existingMaterial Optional existing material to be replaced.
		 */
		public function setChildMaterial(child:DisplayObject3D, material:MaterialObject3D, existingMaterial:MaterialObject3D=null):void 
		{	
			if(!child) 
				return;	
			
			if(!existingMaterial || child.material === existingMaterial)
				child.material = material;
				
			if(child.geometry && child.geometry.faces)
			{
				for each( var triangle:Triangle3D in child.geometry.faces )
				{
					if(!existingMaterial || triangle.material === existingMaterial)
						triangle.material = material;
				}
			}
		}
		
		/**
		 * <span lang="ja">子の名前で、子 DisplayObject3D の為にマテリアルを設定します。</span>
		 * <span lang="en">Sets the material for a child DisplayObject3D by the child's name.</span>
		 * 
		 * @param childName The name of the DisplayObject3D.
		 * @param material	The new material for the child.
		 */
		public function setChildMaterialByName(childName:String, material:MaterialObject3D):void 
		{
			setChildMaterial(getChildByName(childName, true), material);
		}
		
		
		
		/**
		 * 
		 * @param	do3d
		 * @param	existingMaterial
		 * @param	newMaterial
		 */
		private function updateMaterials(do3d:DisplayObject3D, existingMaterial:MaterialObject3D, newMaterial:MaterialObject3D):void
		{
			existingMaterial.unregisterObject(do3d);
			
			// register shaded materials with its object
			if(newMaterial is AbstractLightShadeMaterial || newMaterial is ShadedMaterial)
			{
				newMaterial.registerObject(do3d);
			}
					
			if( do3d.material === existingMaterial )
				do3d.material = newMaterial;
					
			if( do3d.geometry && do3d.geometry.faces && do3d.geometry.faces.length )
			{
				for each( var triangle:Triangle3D in do3d.geometry.faces )
				{
					if( triangle.material === existingMaterial )
						triangle.material = newMaterial;
				}
			}
			
			for each(var child:DisplayObject3D in do3d.children)
				updateMaterials(child, existingMaterial, newMaterial);
		}
		
		
		
	
		/**
		* [internal-use] <span lang="ja">対象にカメラの関係をシュミレーションする為に、2次元プレーン上に3次元座標を投影します。</span>
		* <span lang="en">Projects three dimensional coordinates onto a two dimensional plane to simulate the relationship of the camera to subject.</span>
		* <p/>
		* これは、2次元的に3次元シェイプを描写するプロセスにおける最初のステップです。
		* <span lang="en">This is the first step in the process of representing three dimensional shapes two dimensionally.</span>
		*
	 	* @param	parent	The DisplayObject3D object that contains this display object.
		* @param	renderSessionData Data for the current render.
		*/
		public function project( parent :DisplayObject3D, renderSessionData:RenderSessionData):Number
		{
			if( this._transformDirty ) updateTransform();
	
			this.world.calculateMultiply( parent.world, this.transform );
			
			if( renderSessionData.camera.culler )
			{
				if( this === renderSessionData.camera )
					this.culled = true;
				else
					this.culled = (renderSessionData.camera.culler.testObject(this) < 0);
				if( this.culled ){
					renderSessionData.renderStatistics.culledObjects ++ ;
					return 0;
				} 			
			}
			else
			{
				this.culled = false;
			}
			
			if( parent !== renderSessionData.camera )
			{
				if(renderSessionData.camera.useProjectionMatrix)
					this.view.calculateMultiply4x4( parent.view, this.transform );
				else
					this.view.calculateMultiply( parent.view, this.transform );
			}
			else
			{
				if(renderSessionData.camera.useProjectionMatrix)
					this.view.calculateMultiply4x4( renderSessionData.camera.eye, this.transform );
				else
					this.view.calculateMultiply( renderSessionData.camera.eye, this.transform );
			}
			
			if(_autoCalcScreenCoords){
				calculateScreenCoords(renderSessionData.camera);
			}
			
			var screenZs :Number = 0;
			var children :Number = 0;
					
			for each( var child:DisplayObject3D in this._childrenByName )
			{
				if( child.visible )
				{
					screenZs += child.project( this, renderSessionData );
					children++;
				}
			}
	
			return this.screenZ = screenZs / children;
		}
		
		
		
		/**
		 * 
		 */
		public function calculateScreenCoords( camera :CameraObject3D ):void
		{
			if(camera.useProjectionMatrix)
			{
				var vx	:Number = 0;
				var vy	:Number = 0;
				var vz	:Number = 0;
				var w	:Number = vx * view.n41 + vy * view.n42 + vz * view.n43 + view.n44;
				var vpw	:Number = camera.viewport.width / 2;
				var vph	:Number = camera.viewport.height / 2;
				
				screen.x = (vx * view.n11 + vy * view.n12 + vz * view.n13 + view.n14) / w;
				screen.y = (vx * view.n21 + vy * view.n22 + vz * view.n23 + view.n24) / w;
				screen.z = vx * view.n31 + vy * view.n32 + vz * view.n33 + view.n34;
				
				screen.x *= vpw;
				screen.y *= vph;
			}
			else
			{
				var persp:Number = (camera.focus * camera.zoom) / (camera.focus + view.n34);
				screen.x = view.n14 * persp;
				screen.y = view.n24 * persp;
				screen.z = view.n34;
			}
		}
	
		/**
		* <span lang="ja">正面に指定した距離だけ移動します。</span>
		* <span lang="en">Translate the display object in the direction it is facing, i.e. it's positive Z axis.</span>
		*
		* @param	distance	The distance that the object should move forward.
		*/
		public function moveForward  ( distance:Number ):void { translate( distance, FORWARD  ); }
	
		/**
		* <span lang="ja">後ろ向きに指定した距離だけ移動します。</span>
		* <span lang="en">Translate the display object in the opposite direction it is facing, i.e. it's negative Z axis.</span>
		*
		* @param	distance	The distance that the object should move backward.
		*/
		public function moveBackward ( distance:Number ):void { translate( distance, BACKWARD ); }
	
		/**
		* <span lang="ja">左向きに指定した距離だけ移動します。</span>
		* <span lang="en">Translate the display object lateraly, to the left of the direction it is facing, i.e. it's negative X axis.</span>
		*
		* @param	distance	The distance that the object should move left.
		*/
		public function moveLeft     ( distance:Number ):void { translate( distance, LEFT     ); }
	
		/**
		* <span lang="ja">右向きに指定した距離だけ移動します。。</span>
		* <span lang="en">Translate the display object lateraly, to the right of the direction it is facing, i.e. it's positive X axis.</span>
		*
		* @param	distance	The distance that the object should move right.
		*/
		public function moveRight    ( distance:Number ):void { translate( distance, RIGHT    ); }
	
		/**
		* <span lang="ja">上方向に指定した距離だけ移動します。</span>
		* <span lang="en">Translate the display object upwards, with respect to the direction it is facing, i.e. it's positive Y axis.</span>
		*
		* @param	distance	The distance that the object should move up.
		*/
		public function moveUp       ( distance:Number ):void { translate( distance, UP       ); }
	
		/**
		* <span lang="ja">下方向に指定した距離だけ移動します。</span>
		* <span lang="en">Translate the display object downwards, with respect to the direction it is facing, i.e. it's negative Y axis.</span>
		*
		* @param	distance	The distance that the object should move down.
		*/
		public function moveDown     ( distance:Number ):void { translate( distance, DOWN     ); }
	
		// ___________________________________________________________________________________________________
		//                                                                   L O C A L   T R A N S L A T I O N
	
		/**
		* <span lang="ja">与えられた方向に従ってオブジェクトを移動させます。</span>
		* <span lang="en">Move the object along a given direction.</span>
		*
		* @param	distance	The distance that the object should travel.
		* @param	axis		The direction that the object should move towards.
		*/
		public function translate( distance:Number, axis:Number3D ):void
		{
			var vector:Number3D = axis.clone();
	
			if( this._transformDirty ) updateTransform();
	
			Matrix3D.rotateAxis( transform, vector );
	
			this.x += distance * vector.x;
			this.y += distance * vector.y;
			this.z += distance * vector.z;
		}
	
		// ___________________________________________________________________________________________________
		//                                                                         L O C A L   R O T A T I O N
		
		/**
		* オブジェクトが持つローカル座標の X 軸に沿って表示オブジェクトを前方回転、または後方回転させます。
		* Papervision3D2.x では左手座標系を採用しているので、
		* オブジェクトが持つローカル座標の X 軸の正の方向が右側を向く時、pitch の値が正をとる事により、オブジェクトは前方に回転します。
		* (言いかえれば、飛行機の翼を X 軸として、pitch を上げる事により機首が下がり、尾翼が上がる様なイメージです。)
		*  
		* <span lang="en">Rotate the display object around its lateral or transverse axis ?an axis running from the pilot's left to right in piloted aircraft, 
		* and parallel to the wings of a winged aircraft; thus the nose pitches up and the tail down, or vice-versa.</span>
		*/
		public function get localRotationX():Number
		{
			return Papervision3D.useDEGREES ? _localRotationX * toDEGREES : _localRotationX;
		}
		public function set localRotationX( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;

			if( this._transformDirty ) updateTransform();

			_qPitch.setFromAxisAngle(transform.n11, transform.n21, transform.n31, _localRotationX-angle );
			
			this.transform.calculateMultiply3x3( _qPitch.matrix , transform );
			
			_localRotationX = angle;
			
			_rotationDirty = true;
		}
		
		
		
		/**
		* <span lang="ja">オブジェクトが持つローカル座標の Y 軸に沿って表示オブジェクトを左転回、または右転回させます。</span>
		* <span lang="en">Rotate the display object around about the vertical axis ?an axis drawn from top to bottom.</span>
		*/
		public function get localRotationY():Number
		{
			return Papervision3D.useDEGREES ? _localRotationY * toDEGREES : _localRotationY;
		}
		public function set localRotationY( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;

			if( _transformDirty ) updateTransform();

			_qYaw.setFromAxisAngle( transform.n12, transform.n22, transform.n32, _localRotationY-angle );

			transform.calculateMultiply3x3( _qYaw.matrix, transform );
			
			_localRotationY = angle;
			
			_rotationDirty = true;
		}
		
		
		
		/**
		* <span lang="ja">オブジェクトが持つローカル座標の Z 軸に沿って表示オブジェクトを左回転、または右回転させます。</span>
		* <span lang="en">Rotate the display object around the longitudinal axis ?an axis drawn through the body of the vehicle from tail to nose in the normal direction of flight, or the direction the object is facing.</span>
		*/
		public function get localRotationZ():Number
		{
			return Papervision3D.useDEGREES ? _localRotationZ * toDEGREES : _localRotationZ;
		}
		public function set localRotationZ( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;
	
			if( _transformDirty ) updateTransform();

			_qRoll.setFromAxisAngle( transform.n13, transform.n23, transform.n33, _localRotationZ-angle );
			
			transform.calculateMultiply3x3( _qRoll.matrix, transform );
			
			_localRotationZ = angle;
			
			_rotationDirty = true;
		}
		
		
		
		/**
		* <span lang="ja">オブジェクトが持つローカル座標の X 軸に沿って表示オブジェクトを前方回転、または後方回転させます。</span>
		* <span lang="en">Rotate the display object around its lateral or transverse axis ?an axis running from the pilot's left to right in piloted aircraft, and parallel to the wings of a winged aircraft; thus the nose pitches up and the tail down, or vice-versa.</span>
		*
		* @param	angle	回転角度です。
		*/
		public function pitch( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;

			if( this._transformDirty ) updateTransform();

			_qPitch.setFromAxisAngle(transform.n11, transform.n21, transform.n31, angle );
			
			this.transform.calculateMultiply3x3( _qPitch.matrix , transform );

			_localRotationX += angle;
			
			_rotationDirty = true;
		}
	
		/**
		* <span lang="ja">オブジェクトが持つローカル座標の Y 軸に沿って表示オブジェクトを左転回、または右転回させます。</span>
		* <span lang="en">Rotate the display object around about the vertical axis ?an axis drawn from top to bottom.</span>
		*
		* @param	angle	回転角度です。
		*/
		public function yaw( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;

			if( _transformDirty ) updateTransform();

			_qYaw.setFromAxisAngle( transform.n12, transform.n22, transform.n32, angle );

			transform.calculateMultiply3x3( _qYaw.matrix, transform );
			
			_localRotationY += angle;
			
			_rotationDirty = true;
		}
		
		/**
		* <span lang="ja">オブジェクトが持つローカル座標の Z 軸に沿って表示オブジェクトを左回転、または右回転させます。</span>
		* <span lang="en">Rotate the display object around the longitudinal axis ?an axis drawn through the body of the vehicle from tail to nose in the normal direction of flight, or the direction the object is facing.</span>
		*
		* @param	angle	回転角度です。
		*/
		public function roll( angle:Number ):void
		{
			angle = Papervision3D.useDEGREES? angle * toRADIANS : angle;
	
			if( _transformDirty ) updateTransform();

			_qRoll.setFromAxisAngle( transform.n13, transform.n23, transform.n33, angle );
			
			transform.calculateMultiply3x3( _qRoll.matrix, transform );
			
			_localRotationZ += angle;
			
			_rotationDirty = true;
		}
	
		/**
		* <span lang="ja">引数に受け取ったオブジェクトの方向を向くように回転させます。</span>
		* <span lang="en">Make the object look at a specific position.</span>
		*
		* @param	targetObject	向かせたいオブジェクトです。
		* @param	upAxis			The vertical axis of the universe. Normally the positive Y axis.
		*/
		public function lookAt( targetObject:DisplayObject3D, upAxis:Number3D=null ):void
		{	
			var parent:DisplayObject3D;
			
			// TODO:
			// For lookAt() to work *before* any render we need to calc #world, as
			// #world maybe not set (ie: project() wasn't called yet).
			// We need a better 'dirty' system.
			//
			// Also camera's are now handled differently due to current code.
			// Camera's should act as default DO3D's
			
			if(this is CameraObject3D)
			{
				_position.reset( this.x, this.y, this.z );
			}
			else
			{
				parent = this.parent as DisplayObject3D;
				if(parent)
					world.calculateMultiply(parent.world, transform);
				else
					world.copy(transform);
				_position.reset( world.n14, world.n24, world.n34 );
			}
			
			if(targetObject is CameraObject3D)
			{
				_lookatTarget.reset( targetObject.x, targetObject.y, targetObject.z );
			}
			else
			{
				parent = targetObject.parent as DisplayObject3D;
				if(parent)
					targetObject.world.calculateMultiply(parent.world, targetObject.transform);
				else
					targetObject.world.copy(targetObject.transform);
				_lookatTarget.reset( targetObject.world.n14, targetObject.world.n24, targetObject.world.n34 );
			}
				
			_zAxis.copyFrom(_lookatTarget); 
			_zAxis.minusEq(_position); 
			_zAxis.normalize();
	
			if( _zAxis.modulo > 0.1 )
			{
				_xAxis = Number3D.cross( _zAxis, upAxis || UP, _xAxis );
				_xAxis.normalize();
	
				_yAxis = Number3D.cross( _zAxis, _xAxis, _yAxis );
				_yAxis.normalize();
	
				var look  :Matrix3D = this.transform;
				// scale fix for lookAt()
				look.n11 =  _xAxis.x * _scaleX;
				look.n21 =  _xAxis.y * _scaleX;
				look.n31 =  _xAxis.z * _scaleX;
				
				look.n12 = -_yAxis.x * _scaleY;
				look.n22 = -_yAxis.y * _scaleY;
				look.n32 = -_yAxis.z * _scaleY;
				
				look.n13 =  _zAxis.x * _scaleZ;
				look.n23 =  _zAxis.y * _scaleZ;
				look.n33 =  _zAxis.z * _scaleZ;

				_localRotationX = _localRotationY = _localRotationZ = 0;
				
				this._transformDirty = false;
				this._rotationDirty = true;
			}
			else
			{
				PaperLogger.error("lookAt error");
			}
		}
	

		/**
		* <span lang="ja">オブジェクトまたは Matrix3D から x,y,z 座標の位置情報をコピーします。</span>
		* <span lang="en">Copies the position information (x, y and z coordinates) from another object or Matrix3D.</span>
		*
		* @param	reference	A DisplayObject3D or Matrix3D object to copy the position from.
		*/
		public function copyPosition( reference:* ):void
		{
			var trans  :Matrix3D = this.transform;
			var matrix :Matrix3D = (reference is DisplayObject3D)? reference.transform : reference;
	
			trans.n14 = matrix.n14;
			trans.n24 = matrix.n24;
			trans.n34 = matrix.n34;
		}
	
		/**
		* <span lang="ja">オブジェクトまたは Matrix3D から位置、ローテーション、スケールの情報をコピーします。</span>
		* <span lang="en">Copies the transformation information (position, rotation and scale) from another object or Matrix3D.</span>
		*
		* @param	reference	A DisplayObject3D or Matrix3D object to copy the position from.
		*/
		public function copyTransform( reference:* ):void
		{
			if(reference is DisplayObject3D)
			{
				var do3d:DisplayObject3D = DisplayObject3D(reference);
				if(do3d._transformDirty){
					do3d.updateTransform();
				}
			}
			
			var trans  :Matrix3D = this.transform;
			var matrix :Matrix3D = (reference is DisplayObject3D)? reference.transform : reference;
	
			trans.n11 = matrix.n11;		trans.n12 = matrix.n12;
			trans.n13 = matrix.n13;		trans.n14 = matrix.n14;
	
			trans.n21 = matrix.n21;		trans.n22 = matrix.n22;
			trans.n23 = matrix.n23;		trans.n24 = matrix.n24;
	
			trans.n31 = matrix.n31;		trans.n32 = matrix.n32;
			trans.n33 = matrix.n33;		trans.n34 = matrix.n34;
	
			this._transformDirty = false;
			this._rotationDirty  = true;
		}
	
		// ___________________________________________________________________________________________________
	
		/**
		* <span lang="ja">指定されたオブジェクトのストリング表現を返します。</span>
		* <span lang="en">Returns a string value representing the three-dimensional position values of the display object instance.</span>
		*
		* @return	オブジェクトのストリング表現です。
		*/
		public override function toString(): String
		{
			return this.name + ': x:' + Math.round(this.x) + ' y:' + Math.round(this.y) + ' z:' + Math.round(this.z);
		}

		public function createViewportLayer(viewport:Viewport3D, recurse:Boolean = true):ViewportLayer
		{
			//Register it here under the correct viewport.
			var layer:ViewportLayer = viewport.getChildLayer(this, true);
		
			if(recurse)
				addChildrenToLayer(this, layer);
				
			return layer;		
			
		}
		
		public function addChildrenToLayer(do3d:DisplayObject3D, layer:ViewportLayer):void{
			for each(var obj:DisplayObject3D in do3d.children){
				layer.addDisplayObject3D(obj);
				obj.addChildrenToLayer(obj, layer);
			}
		}
		
		protected function setParentContainer(parent:DisplayObject3D, assign:Boolean = true):void{
			
			if(assign && parent != this)
				parentContainer = parent;
				
			for each(var do3d:DisplayObject3D in children){
				
				do3d.setParentContainer(parent, assign);
			}
		}	
		
		/**
		* [internal-use] <span lang="ja">最初のローテーション、スケール値で Matrix3D 変換を更新します。</span>
		* <span lang="en">Updates the transform Matrix3D with the current rotation and scale values.</span>
		*/
		// TODO OPTIMIZE (HIGH)
		public function updateTransform():void
		{	
			_rot.setFromEuler(_rotationY, _rotationZ, _rotationX);

			// Rotation
			this.transform.copy3x3( _rot.matrix );
	
			// Scale
			_tempMatrix.reset(); 
			_tempMatrix.n11 = this._scaleX;
			_tempMatrix.n22 = this._scaleY;
			_tempMatrix.n33 = this._scaleZ;
			this.transform.calculateMultiply( this.transform, _tempMatrix );
			
			_transformDirty = false;
		}
		
		// Update rotation values
		private function updateRotation():void
		{			
			_tempScale.x = Papervision3D.usePERCENT ? _scaleX * 100 : _scaleX;
			_tempScale.y = Papervision3D.usePERCENT ? _scaleY * 100 : _scaleY;
			_tempScale.z = Papervision3D.usePERCENT ? _scaleZ * 100 : _scaleZ;
			
			_rotation = Matrix3D.matrix2euler(this.transform, _rotation, _tempScale);
			
			this._rotationX = _rotation.x * toRADIANS;
			this._rotationY = _rotation.y * toRADIANS;
			this._rotationZ = _rotation.z * toRADIANS;
	
			this._rotationDirty = false;
		}

	}
}
